/***************************************************************************************************
  *Copyright(C),2010-2017,Sumscope
  *FileName	:  common_util.h
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2019/09/26
  *Desc		:  //用于主要说明此程序文件完成的主要功能
  *Relation :  
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#ifndef COMMON_UTIL_H_F7F36C05_D470_4E60_A2FF_C96E6A1D075F
#define COMMON_UTIL_H_F7F36C05_D470_4E60_A2FF_C96E6A1D075F
#include "portability.h"
#include <cstring>
#include <string>
#include <assert.h>
#include "../extdef.h"
#include "TableCodecCommon.h"
namespace qb{
	namespace proto{
		struct strinfo{
			int		pos, len;
		public:
			bool operator==(const strinfo& si){ return pos == si.pos && len == si.len; }
		};

		class SSPROTOAPI StringUtil{
		public:
			static int SplitStringInfo(const char* str, int size, const std::string& key, strinfo* strings, int capcity);
		};
		class SSPROTOAPI MathUtil{
		public:
			static int itoa(int number, char* buf, int cap);
			static int ftoa(double number, char* buf, int cap, int maxbits = 6);
			static i64 atoi(const char* str, int* plen = NULL);
			static double atof(const char* str);
		};
		SSPROTOAPI void DbgError(char* smt, char* file, char* func, int line, const char* format, ...);

		template<typename T>
		class StackArrayImpl{
			T*			m_ptr;			// 指向堆上的数据,有可能与m_buf相等
			int			m_capcity;		// 堆内存m_ptr的实际空间大小
			int			m_size;			// 对内存m_ptr或者栈内存m_buf中装载的数据大小
			T*			m_buf;			// 指向栈上的数据
		public:
			StackArrayImpl(T* buf, int capcity) :m_size(0), m_capcity(capcity), m_ptr(buf), m_buf(buf)
			{

			}
			~StackArrayImpl()
			{
				if (m_ptr && m_ptr != m_buf)
					delete[] m_ptr;
			}
			void Add(const T& buf){
				Add(&buf, 1);
			}
			void Add(const T* buf, int size)
			{
				if (buf == 0||size<=0)return;
				if (sizeof(T) == sizeof(char))
				{
					size = size <= 0 ? strlen((const char*)buf) : size;
				}
				if (size <= 0)return;
				if (m_ptr == m_buf && m_size + size < m_capcity)
				{
					memcpy(m_buf + m_size, buf, size*sizeof(T));
					m_size += size;
				}
				else
				{
					int extra = size + 1;
					int half = m_size / 2;
					int plus = extra < half ? half : extra;
					T* mem = new T[m_size + plus];
					memcpy(mem, m_ptr, m_size*sizeof(T));
					memcpy(mem + m_size, buf, size*sizeof(T));
					memset(mem + m_size + size, 0, (plus - size)*sizeof(T));
					if (m_ptr && m_ptr != m_buf)
						delete[] m_ptr;
					m_ptr = mem;
					m_capcity = m_size + plus - 1;
					m_size = m_size + size;
				}
			}

			operator const T*()const{ return m_ptr; }
			operator T*(){ return m_ptr; }
			int size()const{ return m_size; }
			T* GetBuf()const{ return m_ptr; }
			const T& at(int pos)const{ return m_ptr[pos]; }
			T& at(int pos){ return m_ptr[pos]; }
			void SetSizeImpl(int size, int N)
			{
				if (m_ptr != m_buf)//堆
				{
					if (size > N)
					{
						if (size > m_capcity)
						{
							if (m_ptr)delete[] m_ptr;
							m_ptr = new T[size];
							m_capcity = size;
						}
						m_size = size;
						memset(m_ptr, 0, sizeof(T)*m_capcity);
					}
					else
					{
						if (m_ptr)delete[] m_ptr;
						m_ptr = m_buf;
						m_capcity = N;
						m_size = size;
					}
				}
				else
				{
					m_capcity = N;
					m_size = size;
				}
			}

			void Reserve(int cap)
			{
				if (cap > m_capcity)
				{
					if (m_ptr != m_buf && m_ptr)
						delete[] m_ptr;
					m_ptr = new T[cap];
					m_capcity = cap;
				}
				m_size = cap;
			}
			void Clear(){
				// 清除,以便可以再装载,复用内存
				m_size = 0;
				if (m_ptr && m_ptr != m_buf && m_capcity > 0)
					memset(m_ptr, 0, m_capcity);
			}
		};
		template<typename T, int N>
		class  SSPROTOAPI StackArray : public StackArrayImpl<T>{				// 当加入的内容小于N，那么在栈上分配,超过配额在堆上分配
			T		m_real_buf[N];		// 
		public:
			StackArray() :StackArrayImpl<T>::StackArrayImpl(m_real_buf, N){
				memset(m_real_buf, 0, sizeof(T)*N);
			}
			StackArray(int capcity) :StackArrayImpl<T>::StackArrayImpl(m_real_buf, N){
				StackArrayImpl<T>::Reserve(capcity);
			}
			StackArray(const T* t, int count) :StackArrayImpl<T>::StackArrayImpl(m_real_buf, N){
				StackArrayImpl<T>::Reserve(count);
				if (t!=0 && count>0)
					memcpy(StackArrayImpl<T>::GetBuf(), t, count*sizeof(T));
			}
			int StackCapcity()const{ return N; }
			void Reset()
			{
				memset(m_real_buf, 0, sizeof(T)*N);
				StackArrayImpl<T>::Clear();
			}
			void SetSize(int size){
				memset(m_real_buf, 0, sizeof(T)*N);
				StackArrayImpl<T>::SetSizeImpl(size, N);
			}
		};

#ifndef MAX
#define MAX(a,b)            (((a) > (b)) ? (a) : (b))
#endif

#ifndef MIN
#define MIN(a,b)            (((a) < (b)) ? (a) : (b))
#endif

	}//namespace base;
}//namespace ss;

#define FMTBUF(buf,fmt,...)				_snprintf_s(buf,_TRUNCATE,fmt,##__VA_ARGS__)

#ifdef _WINDOWS
#define USE_BASE_ASSERT
#endif

#ifdef USE_BASE_ASSERT
#define BASSERT(smt)  (void)( (!!(smt)) || (qb::proto::DbgError(#smt,__FILE__,__FUNCTION__,__LINE__,""), 0) )
#define BASSERTS(smt,fmt,...)    (void)( (!!(smt)) || (qb::proto::DbgError(#smt,__FILE__,__FUNCTION__,__LINE__,fmt,__VA_ARGS__), 0) )
#define BASSERTIF(v,smt)  {if(v){(void)( (!!(smt)) || (qb::proto::DbgError(#smt,__FILE__,__FUNCTION__,__LINE__,""), 0) );}}
#define BASSERT_VOID(smt)  if(!(smt)){qb::proto::DbgError(#smt,__FILE__,__FUNCTION__,__LINE__,"");return;}
#define BASSERT_FALSE(smt) if(!(smt)){qb::proto::DbgError(#smt,__FILE__,__FUNCTION__,__LINE__,"");return false;}
#define BASSERT_NULL(smt)  if(!(smt)){qb::proto::DbgError(#smt,__FILE__,__FUNCTION__,__LINE__,"");return 0;}

#else
#define BASSERT(smt)	assert(smt)
#define BASSERTS(smt,fmt,...)	assert(smt)
#define BASSERTIF(v,smt)
#define BASSERT_VOID(smt)
#define BASSERT_FALSE(smt) 
#define BASSERT_NULL(smt)
#endif // USE_BASE_ASSERT
#endif
